/* Project3: directory.cc

	Modifications by: Cary Rivet
	Added: preprocessor definitions of variables 
	
	NumIndirect - the number of indirect pointers in a list of indirect pointers
	type3_minSize - the mininimum size for a file of type 3
	type2_minSize - the mininimum size for a file of type 2
	
	bool AddDir();
	edited EVERY FUNCTION OF THIS CLASS except fetchfrom and writeback

*/


// directory.cc 
//	Routines to manage a directory of file names.
//
//	The directory is a table of fixed length entries; each
//	entry represents a single file, and contains the file name,
//	and the location of the file header on disk.  The fixed size
//	of each directory entry means that we have the restriction
//	of a fixed maximum size for file names.
//
//	The constructor initializes an empty directory of a certain size;
//	we use ReadFrom/WriteBack to fetch the contents of the directory
//	from disk, and to write back any modifications back to disk.
//
//	Also, this implementation has the restriction that the size
//	of the directory cannot expand.  In other words, once all the
//	entries in the directory are used, no more files can be created.
//	Fixing this is one of the parts to the assignment.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "utility.h"
#include "filehdr.h"
#include "disk.h"					// included these for use of 
#include "system.h"			// synchDisk read/write
#include "directory.h"

// Begin Modifications by Cary RIvet for Project 4

//----------------------------------------------------------------------
// Directory::Directory
// 	Initialize a directory; initially, the directory is completely
//	empty.  If the disk is being formatted, an empty directory
//	is all we need, but otherwise, we need to call FetchFrom in order
//	to initialize it from disk.
//
//	"size" is the number of entries in the directory
//----------------------------------------------------------------------

// made more accurate empty entries
Directory::Directory(int size)
{
    table = new DirectoryEntry[size];
    tableSize = size;
    for (int i = 0; i < tableSize; i++){
		table[i].inUse = FALSE;
		table[i].isDir = false;
		sprintf(table[i].name,"_" );	// mark as unpopulated
		table[i].sector = -1;
		table[i].grandpa = -1;
	}
}

//----------------------------------------------------------------------
// Directory::~Directory
// 	De-allocate directory data structure.
//----------------------------------------------------------------------

Directory::~Directory()
{ 
    delete [] table;
} 

//----------------------------------------------------------------------
// Directory::FetchFrom
// 	Read the contents of the directory from disk.
//
//	"file" -- file containing the directory contents
//----------------------------------------------------------------------

void
Directory::FetchFrom(OpenFile *file)		// account for the "@" & "_" case
{
    (void) file->ReadAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);
}

//----------------------------------------------------------------------
// Directory::WriteBack
// 	Write any modifications to the directory back to disk
//
//	"file" -- file to contain the new directory contents
//----------------------------------------------------------------------

void
Directory::WriteBack(OpenFile *file)	// account for the "@" & "_" case
{

    (void) file->WriteAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);
}

//----------------------------------------------------------------------
// Directory::FindIndex
// 	Look up file name in directory, and return its location in the table of
//	directory entries.  Return -1 if the name isn't in the directory.
//
//	"name" -- the file name to look up
//----------------------------------------------------------------------

// added ability to search indirect tables
int
Directory::FindIndex(char *name)  // account for the "@" & "_" case 
												// (keep incrementing and just calculate the different tables)
{
	int currentTable = 0;

	int i;	// index (offset from the first file)
	
	char clearName[FileNameMaxLen+1];
	sprintf(clearName,"_");
	
	if(!table[0].inUse){
		return -1;	
	}
	
	
	
	// search base table (return if find file)
    for ( i = 0; i < tableSize; i++)
        if (table[i].inUse && strncmp(table[i].name, name, FileNameMaxLen) == 0)
	    	return i;
	
	char tablelink[FileNameMaxLen+1];
	sprintf(tablelink,"@");
	
	//printf("filename in slot 11 %s. \n\n", table[tableSize-1].name);
	if(strcmp(table[tableSize-1].name, tablelink) != 0){
		
		return -1;	
	}
	
	//printf("got past check. \n\n");
		
	// search indirect pointers
	DirectoryEntry indTable[tableSize];
	synchDisk->ReadSector(table[tableSize-1].sector, (char*)indTable );
	
	i--; // account for shared indexes of links
	
	// search through the indirect list
	for(int j = 0; j < tableSize; j++, i++){
		 if (indTable[j].inUse && strncmp(indTable[j].name, name, FileNameMaxLen) == 0)
	    	return i;		
	}
	
	i--; // account again
	
	while(strcmp(indTable[tableSize-1].name, tablelink) == 0){
		
		synchDisk->ReadSector(indTable[tableSize-1].sector, (char*)indTable );
	
		for(int j = 0; j < tableSize; j++, i++){
			 if (indTable[j].inUse && strncmp(indTable[j].name, name, FileNameMaxLen) == 0)
				return i;		
		}
		
		i--; // do it again
			
	}
	
	//printf("didnt find file. \n\n");
	
	
    return -1;		// name not in directory
}

//----------------------------------------------------------------------
// Directory::Find
// 	Look up file name in directory, and return the disk sector number
//	where the file's header is stored. Return -1 if the name isn't 
//	in the directory.
//
//	"name" -- the file name to look up
//----------------------------------------------------------------------
// added ability to search indirect tables
int
Directory::Find(char *name)  // account for the "@" & "_" case
										// (keep incrementing and just calculate the different tables)
{
    int i = FindIndex(name);

	//printf("sector found in findIndex %d. \n\n", i);
		
    if (i != -1){
		
		if(i < tableSize-1){
			
			return table[i].sector;
		
		}else{
			
			char tablelink[FileNameMaxLen+1];
			sprintf(tablelink,"@");
	
			// if the last sector of the table is the element return it
			if(i == tableSize-1){
				if(strncmp(table[i].name,tablelink,FileNameMaxLen) != 0)
					return table[i].sector;		// if wasn't a pointer then it is the dir element
			}
			
			// OTHERWISE
			// look in the indirect pointers by with offset i
			
			i -= (tableSize-1);	// adjust i for current table offset
			
			// prime the loop with the first indirect table
			char lastElement[FileNameMaxLen+1];
			sprintf(lastElement, "%s",table[tableSize-1].name);
			
			// read in the 1st indirect table
			DirectoryEntry indTable[tableSize];
			synchDisk->ReadSector(table[tableSize-1].sector, (char*)indTable);
				
			
			// while there are indirect pointers keep looking
			while(strncmp(lastElement,tablelink,FileNameMaxLen) == 0){
			
				
				// look through indirect pointers if index is within the current table
				if(i<tableSize && i >= 0 ){
					if(strncmp(indTable[i].name,tablelink,FileNameMaxLen) !=0 )
						return indTable[i].sector;		// found entry in this table
				}
				
				sprintf(lastElement, "%s",indTable[tableSize-1].name);
				synchDisk->ReadSector(indTable[tableSize-1].sector, (char*)indTable); // get the next table
				i -= (tableSize - 1);		// adjust i since searched current table
			}
		}
	}
	
	return -1;  // didnt find the file/directory in the list of directory entries

	
}
	
char*
Directory::getChildNameBySector(int sect){
		
	char *buffer = new char[FileNameMaxLen+1];	
		
	char tablelink[FileNameMaxLen+1];
	sprintf(tablelink,"@");
	
	// look for the sector in the first table
	for(int i = 0; i < tableSize; i++){	
		if(table[i].sector == sect && strcmp(table[i].name, tablelink) != 0)
			sprintf(buffer, table[i].name);
	}
	
	
	
	// it there are indirect pointers look through them
	if(strcmp(table[tableSize-1].name,tablelink) == 0){
		
		// look through the first table
		DirectoryEntry indTable[tableSize];
		
		synchDisk->ReadSector(table[tableSize-1].sector, (char*)indTable);
			
		
		for(int i = 0; i < tableSize; i++){
			if(indTable[i].sector == sect && strcmp(indTable[i].name, tablelink) != 0)
				sprintf(buffer,indTable[i].name);
		}
		
		// otherwise keep looking through indirect tables
		
		
		
		while(strcmp(indTable[tableSize-1].name,tablelink) == 0){			
			// read the next table if ther is one
			synchDisk->ReadSector(indTable[tableSize-1].sector, (char*)indTable);
			
			for(int i = 0; i < tableSize; i++){
				if(indTable[i].sector == sect && strcmp(indTable[i].name, tablelink) != 0)
					sprintf(buffer, indTable[i].name);
			}		
		}
		
		return buffer;
	
	}else{
	
		return buffer;
	}
	
}	


//----------------------------------------------------------------------
// Directory::Add
// 	Add a file into the directory.  Return TRUE if successful;
//	return FALSE if the file name is already in the directory, or if
//	the directory is completely full, and has no more space for
//	additional file names.
//
//	"name" -- the name of the file being added
//	"newSector" -- the disk sector containing the added file's header
//----------------------------------------------------------------------
// added ability to create indirect tables and write them to the disk/bitmap
bool
Directory::Add(char *name, int newSector, BitMap* bitmap)  
{ 
    if (FindIndex(name) != -1)
	return FALSE;
	
	//populate the main table if not full yet and get out
    for (int i = 0; i < tableSize; i++)
        if (!table[i].inUse) {
            table[i].inUse = TRUE;
			table[i].isDir = FALSE;
            strncpy(table[i].name, name, FileNameMaxLen); 
            table[i].sector = newSector;
			return TRUE;
		}
		
	// otherwise must look through all indirect tables for the last element	
		
		
	// if got to here all spaces were taken
	// generate a new indirect table if there isnt one
	
	char tablelink[FileNameMaxLen+1];
	sprintf(tablelink,"@");
	
	// if the last element is not a link create a new table set the 
	// last element of the current table to the link, and move
	// the former last element and the new item into the newly
	// generated table
	if(strcmp(table[tableSize-1].name, tablelink) != 0){
		
		// ensure space for the new table in the bitmap
		int newTableSector = bitmap->Find();
		
		// if couldnt find sector for new table return false
		if(newTableSector == -1)
			return FALSE;
		
		
		// create a new indirect table and make every entry empty
		DirectoryEntry indTable[tableSize];		
		
		for (int i = 0; i < tableSize; i++){
			indTable[i].inUse = FALSE;
			sprintf(indTable[i].name,"_" );	// mark as unpopulated
			indTable[i].sector = -1;
			indTable[i].isDir = false;
		}
		
		
		// add the last element of the origional table to the new table
		strcpy(indTable[0].name, table[tableSize-1].name);
		indTable[0].sector = table[tableSize-1].sector;
		indTable[0].inUse = table[tableSize-1].inUse;
		indTable[0].isDir = table[tableSize-1].isDir;
		
		// add the new element into the next slot of the new table
		strcpy(indTable[1].name, name);
		indTable[1].sector = newSector;
		indTable[1].inUse = TRUE;
		indTable[1].isDir = FALSE;
		
		// set the last element of the origional table to link to new table
		sprintf(table[tableSize-1].name,  tablelink);
		table[tableSize-1].isDir = FALSE;
		table[tableSize-1].inUse = TRUE;
		table[tableSize-1].sector = newTableSector;
		
		// write new table to disk
		synchDisk->WriteSector(newTableSector, (char*)indTable); 
		
		return TRUE;
	}
	// if the last was already a link, search through the tables until it finds
	// an available slot
	else{
		
		// keep track of the last element for loop (links)

		char lastElem[FileNameMaxLen+1];
		sprintf(lastElem, table[tableSize-1].name);
		int currentPtrSector = table[tableSize-1].sector;
		
		while(strcmp(lastElem,tablelink) == 0){
			// load the indirect table
			DirectoryEntry indTable[tableSize];
			synchDisk->ReadSector(currentPtrSector, (char*)indTable); 
		
			
			
			// look for a space
			for(int i = 0; i < tableSize; i++){
			
				// if find one set entry values
				if (!indTable[i].inUse) {
					indTable[i].inUse = TRUE;
					indTable[i].isDir = FALSE;
					strncpy(indTable[i].name, name, FileNameMaxLen); 
					indTable[i].sector = newSector;
					synchDisk->WriteSector(currentPtrSector, (char*)indTable);
					
					return TRUE;
				}
			}			
			
			
			
			// if filled and no link in last spot, do new table operations
			if(strcmp(indTable[tableSize-1].name, tablelink) != 0){
		
				// ensure space for the new table in the bitmap
				int newTableSector = bitmap->Find();
				
				// if couldnt find sector for new table return false
				if(newTableSector == -1)
					return FALSE;
				
				
				// create a new indirect table and make every entry empty
				DirectoryEntry indTable2[tableSize];		
				
				for (int i = 0; i < tableSize; i++){
					indTable2[i].inUse = FALSE;
					sprintf(indTable2[i].name,"_" );	// mark as unpopulated
					indTable2[i].sector = -1;
					indTable2[i].isDir = false;
				}
				
				// add the last element of the origional table to the new table
				strcpy(indTable2[0].name, indTable[tableSize-1].name);
				indTable2[0].sector = indTable[tableSize-1].sector;
				indTable2[0].inUse = indTable[tableSize-1].inUse;
				indTable2[0].isDir = indTable[tableSize-1].isDir;
				
				// add the new element into the next slot of the new table
				strcpy(indTable2[1].name, name);
				indTable2[1].sector = newSector;
				indTable2[1].inUse = TRUE;
				indTable2[1].isDir = FALSE;
				
				// set the last element of the origional table to link to new table
				sprintf(indTable[tableSize-1].name, "%s", tablelink);
				indTable[tableSize-1].isDir = FALSE;
				indTable[tableSize-1].inUse = TRUE;
				indTable[tableSize-1].sector = newTableSector;
				
				// write new table to disk
				synchDisk->WriteSector(newTableSector, (char*)indTable2); 
				synchDisk->WriteSector(currentPtrSector, (char*)indTable); 
				
				return TRUE;
			}else{			
				// else repeat with new indirect table
				currentPtrSector = indTable[tableSize-1].sector;
				sprintf(lastElem, indTable[tableSize-1].name);
			}
		}
	}
	
	return FALSE;	// no space. (should never hit this, but just in case)
}

//----------------------------------------------------------------------
// Directory::AddDir
// 	Add a subdirectory into the directory.  Return TRUE if successful;
//	return FALSE if the file name is already in the directory, or if
//	the directory is completely full, and has no more space for
//	additional file names.
//
//	"name" -- the name of the subdirectory being added
//	"newSector" -- the disk sector containing the added file's header
//----------------------------------------------------------------------

// added ability to create indirect tables and write them to the disk/bitmap and mark the directory flag
bool
Directory::AddDir(char *name, int newSector, BitMap* bitmap)	
{ 

//	printf("Called add dir\n");
	
    if (FindIndex(name) != -1)
	return FALSE;
	
	//populate the main table if not full yet and get out
    for (int i = 0; i < tableSize; i++)
        if (!table[i].inUse) {
            table[i].inUse = TRUE;
			table[i].isDir = TRUE;
            strcpy(table[i].name, name); 
            table[i].sector = newSector;
			//printf("I in for loop: %d \n", i);
		//	printf("NAME IN 4 LOOP: %s \n", table[i].name);
		//	printf("The Sector :  %d \n", newSector);
			return TRUE;
		}
		
	// otherwise must look through all indirect tables for the last element	
	//printf("Table [0] : %s\n", table[0].name);	
		
	// if got to here all spaces were taken
	// generate a new indirect table if there isnt one
	
	char tablelink[FileNameMaxLen+1];
	sprintf(tablelink,"@");
	
	// if the last element is not a link create a new table set the 
	// last element of the current table to the link, and move
	// the former last element and the new item into the newly
	// generated table
	if(strcmp(table[tableSize-1].name, tablelink) != 0){
		
		// ensure space for the new table in the bitmap
		int newTableSector = bitmap->Find();
		
		// if couldnt find sector for new table return false
		if(newTableSector == -1)
			return FALSE;
		
		
		// create a new indirect table and make every entry empty
		DirectoryEntry indTable[tableSize];		
		
		for (int i = 0; i < tableSize; i++){
			indTable[i].inUse = FALSE;
			sprintf(indTable[i].name,"_" );	// mark as unpopulated
			indTable[i].sector = -1;
		}
		
		// ****************************************BEGIN FINDING THE LAST ELEMENT
		
		
		// add the last element of the origional table to the new table
		strcpy(indTable[0].name, table[tableSize-1].name);
		indTable[0].sector = table[tableSize-1].sector;
		indTable[0].inUse = table[tableSize-1].inUse;
		indTable[0].isDir = table[tableSize-1].isDir;
		
		// add the new element into the next slot of the new table
		strcpy(indTable[1].name, name);
		indTable[1].sector = newSector;
		indTable[1].inUse = TRUE;
		indTable[1].isDir = TRUE;
		
		// set the last element of the origional table to link to new table
		sprintf(table[tableSize-1].name, "%s", tablelink);
		table[tableSize-1].isDir = FALSE;
		table[tableSize-1].inUse = TRUE;
		table[tableSize-1].sector = newTableSector;
		
		// write new table to disk
		synchDisk->WriteSector(newTableSector, (char*)indTable); 
		
		return TRUE;
	}
	// if the last was already a link, search through the tables until it finds
	// an available slot
	else{
		
		// keep track of the last element for loop (links)
		char lastElem[FileNameMaxLen+1];
		sprintf(lastElem, table[tableSize-1].name);
		int currentPtrSector = table[tableSize-1].sector;
		
		while(strcmp(lastElem,tablelink) == 0){
			// load the indirect table
			DirectoryEntry indTable[tableSize];
			synchDisk->ReadSector(currentPtrSector, (char*)indTable); 
		
			
			
			// look for a space
			for(int i = 0; i < tableSize; i++){
			
				// if find one set entry values
				if (!indTable[i].inUse) {
					indTable[i].inUse = TRUE;
					indTable[i].isDir = TRUE;
					strncpy(indTable[i].name, name, FileNameMaxLen); 
					indTable[i].sector = newSector;
					synchDisk->WriteSector(currentPtrSector, (char*)indTable);
					
					return TRUE;
				}
			}			
			
			
			
			// if filled and no link in last spot, do new table operations
			if(strcmp(indTable[tableSize-1].name, tablelink) != 0){
		
				// ensure space for the new table in the bitmap
				int newTableSector = bitmap->Find();
				
				// if couldnt find sector for new table return false
				if(newTableSector == -1)
					return FALSE;
				
				
				// create a new indirect table and make every entry empty
				DirectoryEntry indTable2[tableSize];		
				
				for (int i = 0; i < tableSize; i++){
					indTable2[i].inUse = FALSE;
					sprintf(indTable2[i].name,"_" );	// mark as unpopulated
					indTable2[i].sector = -1;
					indTable2[i].isDir = false;
				}
				
				// add the last element of the origional table to the new table
				strcpy(indTable2[0].name, indTable[tableSize-1].name);
				indTable2[0].sector = indTable[tableSize-1].sector;
				indTable2[0].inUse = indTable[tableSize-1].inUse;
				indTable2[0].isDir = indTable[tableSize-1].isDir;
				
				// add the new element into the next slot of the new table
				strcpy(indTable2[1].name, name);
				indTable2[1].sector = newSector;
				indTable2[1].inUse = TRUE;
				indTable2[1].isDir = TRUE;
				
				// set the last element of the origional table to link to new table
				sprintf(indTable[tableSize-1].name, "%s", tablelink);
				indTable[tableSize-1].isDir = FALSE;
				indTable[tableSize-1].inUse = TRUE;
				indTable[tableSize-1].sector = newTableSector;
				
				// write new table to disk
				synchDisk->WriteSector(newTableSector, (char*)indTable2); 
				synchDisk->WriteSector(currentPtrSector, (char*)indTable); 
				
				return TRUE;
			}else{			
				// else repeat with new indirect table
				currentPtrSector = indTable[tableSize-1].sector;
				sprintf(lastElem, indTable[tableSize-1].name);
			}
		}
	}
	
	return FALSE;	// no space. (should never hit this, but just in case)
}


//----------------------------------------------------------------------
// Directory::Remove
// 	Remove a file name from the directory.  Return TRUE if successful;
//	return FALSE if the file isn't in the directory. 
//
//	"name" -- the file name to be removed
//----------------------------------------------------------------------

// added ability to remove indirect tables and write them to the disk/bitmap as well as move files within the tables
bool
Directory::Remove(char *name, BitMap* bitmap)				
{ 														
    int i = FindIndex(name); // get the index which will be between 0 and the total number of files in the directory (big number)
	
	
    if (i == -1)
		return FALSE; 		// name not in directory
		
		
	// helper variables for special names in the tables
	char clearName[FileNameMaxLen + 1];	
	char linkName[FileNameMaxLen + 1];
	sprintf(clearName, "_");
	sprintf(linkName, "@");
	
	
	// if the element to remove is within the first table 
	if(i < tableSize){			// name within the first table
		
		// item to remove is within the first table (at most need to store 2 tables)
		
		DirectoryEntry parentTable[tableSize];
		DirectoryEntry childTable[tableSize];
		
		int parentSector = -1;	// sectors of tables that change
		int childSector = -1;
		
		
		DirectoryEntry lastEntry; // the last entry which will be moved into the removed element's spot
		
		// initialize the last element as empty
		sprintf(lastEntry.name, clearName);
		lastEntry.sector = -1;
		lastEntry.isDir = false;
		lastEntry.inUse = false;
		
		
		
		// last element is within the first table
		if(strcmp(table[tableSize-1].name, linkName) != 0){
			
			
			// search the rest of the first table
			for(int j = i+1; j < tableSize; j++){
				if(strcmp(table[j].name, clearName) != 0 && table[j].inUse){
					
					// didnt find last element
					sprintf(lastEntry.name,table[j].name);
					lastEntry.sector = table[j].sector;
					lastEntry.isDir = table[j].isDir;
					lastEntry.inUse = table[j].inUse;				
				}else{ // found last element (j-1)
					
					// clear the last slot
					sprintf(table[j-1].name, clearName);
					table[j-1].sector = -1;
					table[j-1].isDir = false;
					table[j-1].inUse = false;
					
					// copy the last element into the removal slot						
					sprintf(table[i].name, lastEntry.name);
					table[i].sector = lastEntry.sector;
					table[i].isDir = lastEntry.isDir;
					table[i].inUse = lastEntry.inUse;					
				}				
			}
			
			return false;  // couldn't find the last element within the first table (and no link to keep looking)
			
			
		}else{	// last element is in an indirect table
			
			
			// keep track of sector of indirect table
			childSector = table[tableSize-1].sector;
			// copy the indirect table into child
			synchDisk->ReadSector(childSector,(char*)childTable);
			
			// if the child table is the last indirect table
			if(strcmp(childTable[tableSize-1].name, linkName) != 0 || !childTable[tableSize-1].inUse){
				// search the child for the last element
				for(int j = 0; j < tableSize; j++){
					
					// last element not found
					if(strcmp(childTable[j].name, clearName) != 0){
						// didnt find last element
						sprintf(lastEntry.name,childTable[j].name);
						lastEntry.sector = childTable[j].sector;
						lastEntry.isDir = childTable[j].isDir;
						lastEntry.inUse = childTable[j].inUse;							
						
					}else{
						// if was the first element need to remove the indirect table
						if(j-1 == 0){
							
							
							// erase the element from child
							sprintf(childTable[j-1].name, clearName);
							childTable[j-1].sector = -1;
							childTable[j-1].isDir = false;
							childTable[j-1].inUse = false;
							
							// remove the link to the indirect table from main table
							sprintf(table[tableSize-1].name, clearName);
							table[tableSize-1].sector = -1;
							table[tableSize-1].isDir = false;
							table[tableSize-1].inUse = false;
							
							
							// copy last element into removal slot
							sprintf(table[i].name, lastEntry.name);
							table[i].sector = lastEntry.sector;
							table[i].isDir = lastEntry.isDir;
							table[i].inUse = lastEntry.inUse;
							
							
							// make the child's sector available for reuse
							bitmap->Clear(childSector);
							return true;
							
						}else{ // just need to edit the indirect table and copy last element into other slot
							
							// erase the element from child
							sprintf(childTable[j-1].name, clearName);
							childTable[j-1].sector = -1;
							childTable[j-1].isDir = false;
							childTable[j-1].inUse = false;
							
							// special case if the i is a link's index
							if(i == tableSize-1){
								// copy last element into removal slot
								sprintf(childTable[0].name, lastEntry.name);
								childTable[0].sector = lastEntry.sector;
								childTable[0].isDir = lastEntry.isDir;
								childTable[0].inUse = lastEntry.inUse;
								
							}else{
								// copy last element into removal slot
								sprintf(table[i].name, lastEntry.name);
								table[i].sector = lastEntry.sector;
								table[i].isDir = lastEntry.isDir;
								table[i].inUse = lastEntry.inUse;
							}
							
							// make the child's sector available for reuse
							synchDisk->WriteSector(childSector,(char*)childTable);
							return true;
						}
					}
				}
				
				
				return false;  // wasn't in the first table and no links to continue searching
				
				
			}else{	// else search for the last table
				
				
				parentSector = childSector;  // keep track of the parent
				childSector = childTable[tableSize-1].sector;
				
				synchDisk->ReadSector(parentSector, (char*)parentTable);
				synchDisk->ReadSector(childSector, (char*) childTable);
				
				while(strcmp(childTable[tableSize-1].name, linkName) == 0 && childTable[tableSize-1].inUse){
					parentSector = childSector;  // keep track of the parent
					childSector = childTable[tableSize-1].sector;
					
					synchDisk->ReadSector(parentSector, (char*)parentTable);
					synchDisk->ReadSector(childSector, (char*) childTable);
					
					
				}
				
				for(int j = 0; j < tableSize; j++){
					if(strcmp(childTable[j].name, clearName) != 0){ 
						// not last element yet
						sprintf(lastEntry.name,childTable[j].name);
						lastEntry.sector = childTable[j].sector;
						lastEntry.isDir = childTable[j].isDir;
						lastEntry.inUse = childTable[j].inUse;
						
						
					}else{
						if(j-1 == 0){ // last is first element of child
							// erase the element from child
							sprintf(childTable[j-1].name, clearName);
							childTable[j-1].sector = -1;
							childTable[j-1].isDir = false;
							childTable[j-1].inUse = false;
							
							// remove the link to the indirect table from main table
							sprintf(parentTable[tableSize-1].name, clearName);
							parentTable[tableSize-1].sector = -1;
							parentTable[tableSize-1].isDir = false;
							parentTable[tableSize-1].inUse = false;
							
							
							// copy last element into removal slot
							// special case if the i is a link's index
							if(i == tableSize-1){
								
								// 1st indirect table needs to be updated
								DirectoryEntry firstTable[tableSize];
								synchDisk->ReadSector(table[tableSize-1].sector, (char*)firstTable);
								
								// copy the last entry into the first table
								strcpy(firstTable[0].name, lastEntry.name);
								firstTable[0].sector = lastEntry.sector;
								firstTable[0].isDir = lastEntry.isDir;
								firstTable[0].inUse = lastEntry.inUse;
								
								synchDisk->WriteSector(table[tableSize-1].sector, (char*)firstTable);								
								
								
							}else{
								// copy last element into removal slot
								sprintf(table[i].name, lastEntry.name);
								table[i].sector = lastEntry.sector;
								table[i].isDir = lastEntry.isDir;
								table[i].inUse = lastEntry.inUse;											
							}
							// write back parent table
							synchDisk->WriteSector(parentSector, (char*)parentTable);
							
							// make the child's sector available for reuse
							bitmap->Clear(childSector);
							return true;
							
							
						}else{ // otherwise parent stays the same
							
							
							// erase the element from child
							sprintf(childTable[j-1].name, clearName);
							childTable[j-1].sector = -1;
							childTable[j-1].isDir = false;
							childTable[j-1].inUse = false;
							
							// copy last element into removal slot
							// special case if the i is a link's index
							if(i == tableSize-1){
								
								// 1st indirect table needs to be updated
								DirectoryEntry firstTable[tableSize];
								synchDisk->ReadSector(table[tableSize-1].sector, (char*)firstTable);
								
							
								// copy the last entry into the first table
								strcpy(firstTable[0].name, lastEntry.name);
								firstTable[0].sector = lastEntry.sector;
								firstTable[0].isDir = lastEntry.isDir;
								firstTable[0].inUse = lastEntry.inUse;
								
								
								synchDisk->WriteSector(table[tableSize-1].sector, (char*)firstTable);								
								
								
							}else{
								// copy last element into removal slot
								sprintf(table[i].name, lastEntry.name);
								table[i].sector = lastEntry.sector;
								table[i].isDir = lastEntry.isDir;
								table[i].inUse = lastEntry.inUse;											
							}
							
							
							// write back changes to the child table
							synchDisk->WriteSector(childSector, (char*)childTable);
							return true;
						
						}
					}
				}				
				return false; // could not find a place to put the file			
			}			
		}
		
	
	}	else{				// look through indirects (item to remove is in an indirect table)
		
		// retrieve the table with the index to remove
		DirectoryEntry removalTable[tableSize];
		DirectoryEntry parentTable[tableSize];
		DirectoryEntry childTable[tableSize];
		
		
		int removalSector = -1;
		int parentSector = -1;	// sectors of tables that change
		int childSector = -1;
		int removalsParentSector = -1; 
		
		int iOffset = i;  // to calculate the correct table to remove from
		
		// just double checking for a valid link
		if(strcmp(table[tableSize-1].name, linkName) == 0 && table[tableSize-1].inUse){
			
			removalSector = table[tableSize-1].sector;
			synchDisk->ReadSector(removalSector, (char*)removalTable);
			
			// decrement offset to account for table
			iOffset -= (tableSize-1);
			
			while(iOffset > tableSize-1){
				
				removalSector = removalTable[tableSize-1].sector;
				synchDisk->ReadSector(removalSector, (char*)removalTable);				
				iOffset -= (tableSize-1);
			}
			
			// if the the element in the removal table is a link, read one more time
			// and keep track of the parent incase what it points to is the last element
			if(iOffset == tableSize-1){
				removalsParentSector = removalSector;
				removalSector = removalTable[tableSize-1].sector;
				synchDisk->ReadSector(removalSector, (char*)removalTable);							
				iOffset -= (tableSize-1);
			}
			
			// should now have the item to remove's table and it's offset within it's table
			
			
			// look for last element****************************
			
			// see if the removal table is the last indirect
			if( strcmp(removalTable[tableSize-1].name, linkName) != 0 ||  !removalTable[tableSize-1].inUse){
				// if it is the last table
				
				
				DirectoryEntry lastEntry; // the last entry which will be moved into the removed element's spot
		
				// initialize the removal item
				sprintf(lastEntry.name, removalTable[iOffset].name);
				lastEntry.sector = removalTable[iOffset].sector;
				lastEntry.isDir = removalTable[iOffset].isDir;
				lastEntry.inUse = removalTable[iOffset].inUse;
		
				
				
				for(int j = iOffset+1; j < tableSize; j++){
					if(strcmp(removalTable[j].name, clearName) != 0){
						sprintf(lastEntry.name, removalTable[j].name);
						lastEntry.sector = removalTable[j].sector;
						lastEntry.isDir = removalTable[j].isDir;
						lastEntry.inUse = removalTable[j].inUse;
						
					}else{
						
						// account for if the removal element is the first of the removal
						// table and update the parent table
						if(j-1 == 0){ // if removal element is the last one
							
													
							// load parent
							DirectoryEntry remParent[tableSize];
							synchDisk->ReadSector(removalsParentSector, (char*)remParent);
							
							// clear out link to the rem table
							strcpy(remParent[tableSize-1].name, clearName);
							remParent[tableSize-1].sector = -1;
							remParent[tableSize-1].isDir = false;
							remParent[tableSize-1].inUse = false;
							
							// write back parent
							synchDisk->WriteSector(removalsParentSector, (char*)remParent);
							
							// clear removal table's sector
							bitmap->Clear(removalSector);
							return true;							
							
							
						}else{
							
							// clear the last item
							strcpy(removalTable[j-1].name, clearName);
							removalTable[j-1].sector = -1;
							removalTable[j-1].isDir = false;
							removalTable[j-1].inUse = false;
							
							// copy the last element into removal slot
							if(iOffset != j-1){
								strcpy(removalTable[iOffset].name, lastEntry.name);
								removalTable[iOffset].sector = lastEntry.sector;
								removalTable[iOffset].isDir = lastEntry.isDir;
								removalTable[iOffset].inUse = lastEntry.inUse;
							}
							
							
							synchDisk->WriteSector(removalSector, (char*)removalTable);
							return true;							
							
						}
						
					}
					
				}
				
				// remove the last element (couldnt find a blank entry, thus must be the last element)
				strcpy(removalTable[tableSize-1].name, clearName);
				removalTable[tableSize-1].sector = -1;
				removalTable[tableSize-1].isDir = false;
				removalTable[tableSize-1].inUse = false;
				
				// copy the last element into removal slot
				if(iOffset != tableSize-1){
					strcpy(removalTable[iOffset].name, lastEntry.name);
					removalTable[iOffset].sector = lastEntry.sector;
					removalTable[iOffset].isDir = lastEntry.isDir;
					removalTable[iOffset].inUse = lastEntry.inUse;
				}
				
				
				synchDisk->WriteSector(removalSector, (char*)removalTable);
				
				return true;
				
			}else{
				
				// if the removal table is not the last table search for the last element
				
				DirectoryEntry lastEntry; // the last entry which will be moved into the removed element's spot
		
				printf(" looking in indirects after removal\n\n");
				
				// removalsParentSector is correct (shouldn't need, but just in case) 
				// removalSector is correct
				// removalTable is correct
				
				// load the next table as the child table
				childSector = removalTable[tableSize-1].sector;
				synchDisk->ReadSector(childSector, (char*)childTable);
				
				
				// if there are no more tables 
				if(strcmp(childTable[tableSize-1].name, linkName) != 0 || !childTable[tableSize -1].inUse){
		
					printf("only 1 table after removal table\n\n");
		
					// search for the last element in the child table and act appropriately (there are people watching)
		
					// set the last element as the first of the last table
					sprintf(lastEntry.name, childTable[0].name);
					lastEntry.sector = childTable[0].sector;
					lastEntry.isDir = childTable[0].isDir;
					lastEntry.inUse = childTable[0].inUse;
					
					// SEARCH!?!?!???!!!                                                                                okay
					for(int j = 1; j < tableSize; j++){
						
						if(strcmp(childTable[j].name, clearName) != 0){
							sprintf(lastEntry.name, childTable[j].name);
							lastEntry.sector = childTable[j].sector;
							lastEntry.isDir = childTable[j].isDir;
							lastEntry.inUse = childTable[j].inUse;
							
							
						}else{
							
							// account for removing only element of the child table
							if(j-1 == 0){
								
								// need to remove link from removalTable (since it's the parent)
								strcpy(removalTable[tableSize-1].name, clearName);
								removalTable[tableSize-1].sector = -1;
								removalTable[tableSize-1].isDir = false;
								removalTable[tableSize-1].inUse = false;
								
								// write last element into removal slot
								// remove the last element (couldnt find a blank entry, thus must be the last element)
								strcpy(removalTable[iOffset].name, lastEntry.name);
								removalTable[iOffset].sector = lastEntry.sector;
								removalTable[iOffset].isDir = lastEntry.isDir;
								removalTable[iOffset].inUse = lastEntry.inUse;
								
								// clear the sector of the child table from the bitmap
								bitmap->Clear(childSector);
								
								// write back the removalTable
								synchDisk->WriteSector(removalSector, (char*) removalTable);
								return true;
							}else{
								
								// erase the last element 
								strcpy(childTable[j-1].name, clearName);
								childTable[j-1].sector = -1;
								childTable[j-1].isDir = false;
								childTable[j-1].inUse = false;
								
								// copy last element into the removal slot
								strcpy(removalTable[iOffset].name, lastEntry.name);
								removalTable[iOffset].sector = lastEntry.sector;
								removalTable[iOffset].isDir = lastEntry.isDir;
								removalTable[iOffset].inUse = lastEntry.inUse;
								
								// save both tables back to the disk
								synchDisk->WriteSector(removalSector, (char*) removalTable);
								synchDisk->WriteSector(childSector, (char*) childTable);								
								return true;
							}
							
							
						}
						
						
						
					}
					
					// if got past the loop then the child table must be full remove the last element
					strcpy(childTable[tableSize-1].name, clearName);
					childTable[tableSize-1].sector = -1;
					childTable[tableSize-1].isDir = false;
					childTable[tableSize-1].inUse = false;
					
					// copy last element into the removal slot
					strcpy(removalTable[iOffset].name, lastEntry.name);
					removalTable[iOffset].sector = lastEntry.sector;
					removalTable[iOffset].isDir = lastEntry.isDir;
					removalTable[iOffset].inUse = lastEntry.inUse;
					
					// save both tables back to the disk
					synchDisk->WriteSector(removalSector, (char*) removalTable);
					synchDisk->WriteSector(childSector, (char*) childTable);								
					return true;
					
					
					
				}else{	// if there are more tables keep track of child/parent
					
					printf("multiple tables after removal table\n\n");
					
					
					while(strcmp(childTable[tableSize-1].name, linkName) == 0){
						
						parentSector = childSector;
						childSector = childTable[tableSize-1].sector;
						
						synchDisk->ReadSector(parentSector, (char*)parentTable);
						synchDisk->ReadSector(childSector, (char*)childTable);						
					}
					
					
					printf("1st element of last table %s\n\n", childTable[0].name);
					
					
					// set the last element as the first of the last table
					sprintf(lastEntry.name, childTable[0].name);
					lastEntry.sector = childTable[0].sector;
					lastEntry.isDir = childTable[0].isDir;
					lastEntry.inUse = childTable[0].inUse;
					
					// search the child table for the last element
					for(int j = 1; j < tableSize; j++){
						
						if(strcmp(childTable[j].name, clearName) != 0){
							sprintf(lastEntry.name, childTable[j].name);
							lastEntry.sector = childTable[j].sector;
							lastEntry.isDir = childTable[j].isDir;
							lastEntry.inUse = childTable[j].inUse;
							
							
						}else{
							
							if(j-1 == 0){ // if first element of the child table clear child, update parent's link, and move last entry
								
								// remove link to child
								strcpy(parentTable[tableSize-1].name, clearName);
								parentTable[tableSize-1].sector = -1;
								parentTable[tableSize-1].isDir = false;
								parentTable[tableSize-1].inUse = false;
								
								// copy the last element
								strcpy(removalTable[iOffset].name, lastEntry.name);
								removalTable[iOffset].sector = lastEntry.sector;
								removalTable[iOffset].isDir = lastEntry.isDir;
								removalTable[iOffset].inUse = lastEntry.inUse;
								
								// clear the child sector
								bitmap->Clear(childSector);
								
								// write back the parent sector and removal sector
								synchDisk->WriteSector(parentSector, (char*)parentTable);
								synchDisk->WriteSector(removalSector, (char*)removalTable);
								
								
							}else{	// remove last element from child table, and move last entry
								
								// remove the element from the child table
								strcpy(childTable[j-1].name,clearName);
								childTable[j-1].sector = -1;
								childTable[j-1].isDir = false;
								childTable[j-1].inUse = false;
								
								// move over the last element
								strcpy(removalTable[iOffset].name, lastEntry.name);
								removalTable[iOffset].sector = lastEntry.sector;
								removalTable[iOffset].isDir = lastEntry.isDir;
								removalTable[iOffset].inUse = lastEntry.inUse;
								
								// write edited sectors back to the disk
								synchDisk->WriteSector(childSector, (char*)childTable);
								synchDisk->WriteSector(removalSector, (char*)removalTable);
								
								
							}
							
							
							
						}
						
						
						
						
					}
					
					
					
					
					
					
					// if got past the loop then the child table must be full remove the last element
					strcpy(childTable[tableSize-1].name, clearName);
					childTable[tableSize-1].sector = -1;
					childTable[tableSize-1].isDir = false;
					childTable[tableSize-1].inUse = false;
					
					// copy last element into the removal slot
					strcpy(removalTable[iOffset].name, lastEntry.name);
					removalTable[iOffset].sector = lastEntry.sector;
					removalTable[iOffset].isDir = lastEntry.isDir;
					removalTable[iOffset].inUse = lastEntry.inUse;
					
					// save both tables back to the disk
					synchDisk->WriteSector(removalSector, (char*) removalTable);
					synchDisk->WriteSector(childSector, (char*) childTable);								
					return true;
					
					
				}
				
			}	
			
		}else{
			// table index is out of range and unreachable

			return false;
			
		}
	}
	
	printf("Could not remove file 3\n\n");
	return false;	// file was not removed
}

//----------------------------------------------------------------------
// Directory::List
// 	List all the file names in the directory. 
//----------------------------------------------------------------------

// edited to print from indirect tables
void
Directory::List()			// account for the "@" & "_" case
{
	// helper variables for special names in the tables
	char clearName[FileNameMaxLen + 1];	
	char linkName[FileNameMaxLen + 1];
	strcpy(clearName, "_");
	strcpy(linkName,"@");
	
	for (int i = 0; i < tableSize && (strcmp(table[i].name, linkName) != 0 && strcmp(table[i].name, clearName) != 0); i++)
		if (table[i].inUse)
			printf("%s\n", table[i].name);
	

	// if there are links keep printing until reaches last file name
	if(strcmp(table[tableSize-1].name, linkName) == 0){
		
		DirectoryEntry indTable[tableSize];
		synchDisk->ReadSector(table[tableSize-1].sector,(char*)indTable);
				
		for (int i = 0; i < tableSize  && (strcmp(indTable[i].name, linkName) != 0 && strcmp(indTable[i].name, clearName) != 0); i++)
			if (indTable[i].inUse)
				printf("%s\n", indTable[i].name);
	
		while(strcmp(indTable[tableSize-1].name, linkName) == 0){
			synchDisk->ReadSector(indTable[tableSize-1].sector,(char*)indTable);
		
			for (int i = 0; i < tableSize  && (strcmp(indTable[i].name, linkName) != 0 && strcmp(indTable[i].name, clearName) != 0); i++)
				if (indTable[i].inUse)
					printf("%s\n", indTable[i].name);
		}
		
		
	}
	
}

//----------------------------------------------------------------------
// Directory::Print
// 	List all the file names in the directory, their FileHeader locations,
//	and the contents of each file.  For debugging.
//----------------------------------------------------------------------

// edited to print from indirect tables
void
Directory::Print()   // EDIT THIS FOR DIRECTORYS TO JUST PRINT THE NAME
{ 							// account for the "_" case
    FileHeader *hdr = new FileHeader;
	// helper variables for special names in the tables
	char clearName[FileNameMaxLen + 1];	
	char linkName[FileNameMaxLen + 1];
	strcpy(clearName, "_");
	strcpy(linkName, "@");
	
	// print for the first table
    printf("Directory contents:\n");
    for (int i = 0; i < tableSize; i++)
		if (table[i].inUse && (strcmp(table[i].name, linkName) != 0 && strcmp(table[i].name, clearName) != 0)) {
			printf("Name: %s, Sector: %d\n", table[i].name, table[i].sector);
			hdr->FetchFrom(table[i].sector);
			hdr->Print();
		}
		
	// if the last of the first table is a link keep printing links until all files are printed (come a cross a "_")
	
	if(strcmp(table[tableSize-1].name, linkName) == 0){
		
		DirectoryEntry indTable[tableSize];
		synchDisk->ReadSector(table[tableSize-1].sector,(char*)indTable);
		
		for (int i = 0; i < tableSize; i++)
			if (indTable[i].inUse && (strcmp(indTable[i].name, linkName) != 0 && strcmp(indTable[i].name, clearName) != 0)) {
				printf("Name: %s, Sector: %d\n", indTable[i].name, indTable[i].sector);
				hdr->FetchFrom(indTable[i].sector);
				hdr->Print();
			}		
		
		
		while(strcmp(indTable[tableSize-1].name, linkName) == 0){
			
			synchDisk->ReadSector(indTable[tableSize-1].sector,(char*)indTable);
		
			for (int i = 0; i < tableSize; i++)
				if (indTable[i].inUse && (strcmp(indTable[i].name, linkName) != 0 && strcmp(indTable[i].name, clearName) != 0)) {
					printf("Name: %s, Sector: %d\n", indTable[i].name, indTable[i].sector);
					hdr->FetchFrom(indTable[i].sector);
					hdr->Print();
				}			
		}				
	}
    printf("\n");
    delete hdr;
}

// edited to print from indirect tables
void Directory::PrintForLS(){	// made this because list did not work for some reason
										// account for the "@" & "_" case
	
	// helper variables for special names in the tables
	char clearName[FileNameMaxLen + 1];	
	char linkName[FileNameMaxLen + 1];
	strcpy(clearName, "_");
	strcpy(linkName,"@");
	
//	printf("table 0 in LS: %s", table[0].name);
	
	for (int i = 0; i < tableSize && (strcmp(table[i].name, linkName) != 0 && strcmp(table[i].name, clearName) != 0); i++)
		if (table[i].inUse)
			printf("%s\n", table[i].name);
			
	// if there are links keep printing until reaches last file name
	if(strcmp(table[tableSize-1].name, linkName) == 0){
		
		DirectoryEntry indTable[tableSize];
		synchDisk->ReadSector(table[tableSize-1].sector,(char*)indTable);
				
		for (int i = 0; i < tableSize  && (strcmp(indTable[i].name, linkName) != 0 && strcmp(indTable[i].name, clearName) != 0); i++)
			if (indTable[i].inUse)
				printf("%s\n", indTable[i].name);
	
		while(strcmp(indTable[tableSize-1].name, linkName) == 0){
			synchDisk->ReadSector(indTable[tableSize-1].sector,(char*)indTable);
		
			for (int i = 0; i < tableSize  && (strcmp(indTable[i].name, linkName) != 0 && strcmp(indTable[i].name, clearName) != 0); i++)
				if (indTable[i].inUse)
					printf("%s\n", indTable[i].name);
		}
		
		
	}	
			
			
}

// edited to print from indirect tables
void Directory::PrintForLSL(){	// EDIT THIS TO PRINT TYPE (Directory/File)
											// account for the "@" & "_" case
	FileHeader *hdr = new FileHeader;

	// helper variables for special names in the tables
	char clearName[FileNameMaxLen + 1];	
	char linkName[FileNameMaxLen + 1];
	strcpy(clearName, "_");
	strcpy(linkName,"@");
	
	
	
	int size;
	for(int i = 0; i < tableSize; i++){
		if (table[i].inUse && (strcmp(table[i].name, linkName) != 0 && strcmp(table[i].name, clearName) != 0)) {
			printf("Name: %s ", table[i].name);
			printf("Type: ");
			if(table[i].isDir == false){
				printf("File ");
				hdr->FetchFrom(table[i].sector);
				size = hdr->FileLength();
				printf("Size: %d bytes\n", size);
			}else{
				printf("Directory \n");
				
			}
		}
	}
	

	
	if(strcmp(table[tableSize-1].name, linkName) == 0){
	
		DirectoryEntry indTable[tableSize];
		synchDisk->ReadSector(table[tableSize-1].sector,(char*)indTable);
		
		for(int i = 0; i < tableSize; i++){
			if (indTable[i].inUse && (strcmp(indTable[i].name, linkName) != 0 && strcmp(indTable[i].name, clearName) != 0)) {
				printf("Name: %s ", indTable[i].name);
				printf("Type: ");
				if(indTable[i].isDir == false){
					printf("File ");
					hdr->FetchFrom(indTable[i].sector);
					size = hdr->FileLength();
					printf("Size: %d bytes\n", size);
				}else{
					printf("Directory \n");
					
				}
			}
		}
		

		while(strcmp(indTable[tableSize-1].name, linkName) == 0){
		
			synchDisk->ReadSector(indTable[tableSize-1].sector,(char*)indTable);
			
			
			//synchDisk->ReadSector(table[tableSize-1].sector,(char*)indTable);
			
			for(int i = 0; i < tableSize; i++){
			printf("In the for\n");
				if (indTable[i].inUse && (strcmp(indTable[i].name, linkName) != 0 && strcmp(indTable[i].name, clearName) != 0)) {
					printf("Name: %s ", indTable[i].name);
					printf("Type: ");
					if(indTable[i].isDir == false){
						printf("File ");
						hdr->FetchFrom(indTable[i].sector);
						size = hdr->FileLength();
						printf("Size: %d bytes\n", size);
					}else{
						printf("Directory \n");
						
					}
				}
			}
		
		}
		
	}
	
	printf("passed it\n");
	
	delete hdr;
}



void Directory::clearDirFiles( BitMap* bitmap){
	while(table[0].inUse){
		Remove(table[0].name, bitmap);
	}
}


int Directory::getDirectSect(){
	return directSector;
}

void Directory::setParent(int parent){
	table[0].grandpa = parent;
}

int Directory::getParent(){
	return table[0].grandpa;
}





// End Modifications by Cary Rivet Project 4
